tree grammar REAST;

options {
  tokenVocab=RE;
  ASTLabelType = CommonTree;
}

@header {
package compiler.antlr;
import compiler.grammar.*;
import compiler.scanner.nfa.*;
import java.util.Set;
import java.util.HashSet;
}
@members{
}

start[String tokenName] returns [NFAItem result]
	: ^(RE v=alternation) 
	{
		v.getEndState().setAcceptable(true);
		v.getEndState().setToken(tokenName);
		result = v;
	} 
	;

alternation returns [NFAItem result]
	: ^(REOR 
	(v=concat
	{
		if(result == null)
			$result=v;
		else
			$result=NFAUtils.or($result,v);
	}
	)+)
	;
	
concat returns [NFAItem result]
	: ^(REAND 
	(v=kleen 
	{ 
		if(result == null)
			$result=v;
		else
			$result=NFAUtils.cat($result,v);
	}
	)+)
	; 
	
kleen returns [NFAItem result]
	: ^(KLEENE v=lowterm) { $result = NFAUtils.kleen(v); }
	| ^(NOTKLEEN v=lowterm) {$result = v;} // not Kleen, don't modify anything
	;

lowterm returns [NFAItem result] /* returns NFAItem : two states (start and end) with a set of transitions between them */
@init 
{
	NFAState start = new NFAState(),end= new NFAState();
	result = new NFAItem(start,end);	
	NFATransition trans;
}
	: s=SYMBOL 
	{ 
		NFAUtils.transOn(start,end,$s.text.charAt(0));
	}
	| a=alternation /* a bracketed expression. the transition here is not on character, it is on a whole expression */
	{
		NFAUtils.transOn(start,end,a);
	}
	| v=set 
	{
		NFAUtils.transOn(start,end,v);
	}
	;

set returns [Set<Character> result]
@init { result = new HashSet<Character>(); }
 	: ^(SET (v=setElem {result.addAll(v);} )+) 
	;

setElem	returns [Set<Character> result]
@init { result = new HashSet<Character>(); char first,second; }
	: ^(RANGE s1=SYMBOL s2=SYMBOL) 
		{$s1.text.charAt(0) <= $s2.text.charAt(0)}? 
		{
			first = $s1.text.charAt(0); 
			second = $s2.text.charAt(0);
			while(first <= second)
			{
				result.add(first);
				first ++;
			}
		}
	| s=SYMBOL { result.add($s.text.charAt(0)); }
	;
